#!/bin/bash

# Configuration variables (change as you wish)
src="${1:-/path/to/source}"
dst="${2:-/path/to/target}"
backupDepth=${backupDepth:-7}
timeout=${timeout:-1800}
pathBak0="${pathBak0:-data}"
rotationLockFileName="${rotationLockFileName:-.rsync-rotation-lock}"
pathBakN="${pathBakN:-backup}"
nameBakN="${nameBakN:-backup}"
exclusionFileName="${exclusionFileName:-exclude.txt}"
dateCmd="${dateCmd:-date}"
logName="${logName:-rsync-incremental-backup_$(${dateCmd} -Id)_$(${dateCmd} +%H-%M-%S).log}"
ownFolderName="${ownFolderName:-.rsync-incremental-backup}"
logFolderName="${logFolderName:-log}"

# Combinate previously defined variables for use (don't touch this)
ownFolderPath="${HOME}/${ownFolderName}"
tempLogPath="${ownFolderPath}/local_${dst//[\/]/\\}"
exclusionFilePath="${ownFolderPath}/${exclusionFileName}"
bak0="${dst}/${pathBak0}"
rotationLockFilePath="${dst}/${rotationLockFileName}"
logPath="${dst}/${pathBakN}/${logFolderName}"
logFile="${tempLogPath}/${logName}"

# Prepare own folder
mkdir -p "${tempLogPath}"
touch "${logFile}"
touch "${exclusionFilePath}"

writeToLog() {
	echo -e "${1}" | tee -a "${logFile}"
}

writeToLog "********************************"
writeToLog "*                              *"
writeToLog "*   rsync-incremental-backup   *"
writeToLog "*                              *"
writeToLog "********************************"

# Prepare backup paths
i=1
while [ "${i}" -le "${backupDepth}" ]
do
	export "bak${i}=${dst}/${pathBakN}/${nameBakN}.${i}"
	true "$((i = i + 1))"
done

writeToLog "\\n[$(${dateCmd} -Is)] You are going to backup"
writeToLog "\\tfrom:  ${src}"
writeToLog "\\tto:    ${bak0}"

# Prepare paths at destination
mkdir -p "${dst}" "${logPath}"

writeToLog "\\n[$(${dateCmd} -Is)] Old logs sending begins\\n"

# Send old pending logs to destination
rsync -rhv --remove-source-files --exclude="${logName}" --log-file="${logFile}" \
	"${tempLogPath}/" "${logPath}/"

writeToLog "\\n[$(${dateCmd} -Is)] Old logs sending finished"

# Rotate backups if last rsync succeeded ..
if ([ ! -e "${rotationLockFilePath}" ])
then
	# .. and there is previous data
	if [ -d "${bak0}" ]
	then
		writeToLog "\\n[$(${dateCmd} -Is)] Backups rotation begins"

		true "$((i = i - 1))"

		# Remove the oldest backup if exists
		bak="bak${i}"
		rm -rf "${!bak}"

		# Rotate the previous backups
		while [ "${i}" -gt 0 ]
		do
			bakNewPath="bak${i}"
			true "$((i = i - 1))"
			bakOldPath="bak${i}"
			if [ -d "${!bakOldPath}" ]
			then
				mv "${!bakOldPath}" "${!bakNewPath}"
			fi
		done

		writeToLog "[$(${dateCmd} -Is)] Backups rotation finished\\n"
	else
		writeToLog "\\n[$(${dateCmd} -Is)] No previous data found, there is no backups to be rotated\\n"
	fi
else
	writeToLog "\\n[$(${dateCmd} -Is)] Last backup failed, backups will not be rotated\\n"
fi

# Set rotation lock file to detect in next run when backup fails
touch "${rotationLockFilePath}"

writeToLog "[$(${dateCmd} -Is)] Backup begins\\n"

# Do the backup
if rsync -achv --progress --timeout="${timeout}" --delete -W --link-dest="${bak1}/" \
	--log-file="${logFile}" --exclude="${ownFolderPath}" --chmod=+r \
	--exclude-from="${exclusionFilePath}" "${src}/" "${bak0}/"
then
	writeToLog "\\n[$(${dateCmd} -Is)] Backup completed successfully\\n"

	# Clear unneeded partials and lock file
	rm -rf "${rotationLockFilePath}"
	rsyncFail=0
else
	writeToLog "\\n[$(${dateCmd} -Is)] Backup failed, try again later\\n"
	rsyncFail=1
fi

# Send the complete log file to destination
mv "${logFile}" "${logPath}"

exit "${rsyncFail}"
